package com.portalito.android.modelo;

import java.util.ArrayList;
import java.util.Iterator;

import com.portalito.android.Utils;
import com.portalito.android.dto.Almacen;
import com.portalito.android.dto.OrdenCompra;
import com.portalito.android.dto.Producto;
import com.portalito.android.dto.Usuario;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.util.Log;

/* Data Access Object */

public class DAO {
	
	private final static String TAG = "DAO";
	private DB db;
	
	public DAO(Context context) {
		db = new DB(context);
		Log.d(TAG, "DAO inicializado");
	}
	
	public Usuario obtenerUsuario(String usuario, String clave) {
		Cursor cursor = db.obtener("usuarios", String.format("usuario='%s' AND clave='%s' AND activo=1", usuario, clave));
		if(cursor != null) {
			Usuario usuarioDto = new Usuario();
			usuarioDto.setUsuario(cursor.getString(0));
			usuarioDto.setClave(cursor.getString(1));
			usuarioDto.setNombre(cursor.getString(2));
			usuarioDto.setFechaModificacion(cursor.getString(3));
			usuarioDto.setActivo(cursor.getInt(4) != 0);
			usuarioDto.setPermisoRecibir(cursor.getInt(5) != 0);
			cursor.close();		
			ArrayList<Almacen> almacenes = obtenerAlmacenesPorUsuario(usuario);
			Iterator<Almacen> iterator = almacenes.iterator();
			while(iterator.hasNext()) {
				usuarioDto.agregarAlmacen(iterator.next());
			}	
			return usuarioDto;
		}
		return null;
	}
	
	public Usuario obtenerUsuario(String usuario, boolean cargarAlmacenes) {
		Cursor cursor = db.obtener("usuarios", String.format("usuario='%s'", usuario));
		if(cursor != null) {
			Usuario usuarioDto = new Usuario();
			usuarioDto.setUsuario(cursor.getString(0));
			usuarioDto.setClave(cursor.getString(1));
			usuarioDto.setNombre(cursor.getString(2));
			usuarioDto.setFechaModificacion(cursor.getString(3));
			usuarioDto.setActivo(cursor.getInt(4) != 0);
			usuarioDto.setPermisoRecibir(cursor.getInt(5) != 0);
			cursor.close();
			if(cargarAlmacenes) {
				ArrayList<Almacen> almacenes = obtenerAlmacenesPorUsuario(usuario);
				Iterator<Almacen> iterator = almacenes.iterator();
				while(iterator.hasNext()) {
					usuarioDto.agregarAlmacen(iterator.next());
				}
			}
			return usuarioDto;
		}
		return null;
	}
	
	public ArrayList<Almacen> obtenerAlmacenes() {
		ArrayList<Almacen> almacenes = new ArrayList<Almacen>();
		Cursor cursor = db.obtenerTodos("almacenes", null);
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Almacen almacenDto = new Almacen(cursor.getString(0), cursor.getString(1));
				almacenDto.setFechaModificacion(cursor.getString(2));
				almacenes.add(almacenDto);
			}
			cursor.close();
		}
		return almacenes;
	}
	
	public Almacen obtenerAlmacen(String id) {
		Cursor cursor = db.obtener("almacenes", String.format("id='%s'", id));
		if(cursor != null) {
			Almacen almacenDto = new Almacen(cursor.getString(0), cursor.getString(1));
			almacenDto.setFechaModificacion(cursor.getString(2));
			cursor.close();
			return almacenDto;
		}
		return null;
	}
	
	public ArrayList<Almacen> obtenerAlmacenesPorUsuario(String usuario) {
		ArrayList<Almacen> almacenes = new ArrayList<Almacen>();
		Cursor cursor = db.obtenerAlmacenesPorUsuario(usuario);
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Almacen almacenDto = new Almacen(cursor.getString(0), cursor.getString(1));
				almacenDto.setFechaModificacion(cursor.getString(2));
				almacenes.add(almacenDto);
			}
			cursor.close();
		}
		return almacenes;
	}
	
	public ArrayList<OrdenCompra> obtenerOrdenesCompra(String usuario, String almacen) {
		ArrayList<OrdenCompra> ordenes = new ArrayList<OrdenCompra>();
		Cursor cursor = db.obtenerTodos("ordenes", String.format("usuario='%s' AND almacen='%s'", usuario, almacen));
		if(cursor != null) {
			while(cursor.moveToNext()) {
				OrdenCompra ocDto = new OrdenCompra();
				ocDto.setId(cursor.getInt(0));
				ocDto.setUsuario(obtenerUsuario(cursor.getString(1), false));
				ocDto.setAlmacen(obtenerAlmacen(cursor.getString(2)));
				ocDto.setEstado(cursor.getString(3));
				ocDto.setIniciador(cursor.getString(4));
				ocDto.setFecha(cursor.getString(5));
				ocDto.setProveedor(cursor.getString(6));
				ocDto.setFechaModificacion(cursor.getString(7));
				if(OrdenCompra.esValido(ocDto)) {
					ordenes.add(ocDto);
				}
			}
			cursor.close();
		}
		return ordenes;
	}
	
	public ArrayList<OrdenCompra> obtenerOrdenesCompraPorEnviar(String usuario, String almacen) {
		ArrayList<OrdenCompra> ordenes = new ArrayList<OrdenCompra>();
		Cursor cursor = db.obtenerTodos("ordenes", String.format("usuario='%s' AND almacen='%s' AND enviar='1'", usuario, almacen));
		if(cursor != null) {
			while(cursor.moveToNext()) {
				OrdenCompra ocDto = new OrdenCompra();
				ocDto.setId(cursor.getInt(0));
				ocDto.setUsuario(obtenerUsuario(cursor.getString(1), false));
				ocDto.setAlmacen(obtenerAlmacen(cursor.getString(2)));
				ocDto.setEstado(cursor.getString(3));
				ocDto.setIniciador(cursor.getString(4));
				ocDto.setFecha(cursor.getString(5));
				ocDto.setProveedor(cursor.getString(6));
				ocDto.setFechaModificacion(cursor.getString(7));
				if(OrdenCompra.esValido(ocDto)) {
					ArrayList<Producto> productos = obtenerProductos(ocDto.getId());
					Iterator<Producto> i = productos.iterator();
					while(i.hasNext()) {
						ocDto.agregarProducto(i.next());
					}
					ordenes.add(ocDto);
				}
			}
			cursor.close();
		}
		return ordenes;
	}
	
	public OrdenCompra obtenerOrdenCompra(int id, boolean cargarProductos) {
		Cursor cursor = db.obtener("ordenes", String.format("id='%s'", id));
		if(cursor != null) {
			OrdenCompra ocDto = new OrdenCompra();
			ocDto.setId(cursor.getInt(0));
			ocDto.setUsuario(obtenerUsuario(cursor.getString(1), false));
			ocDto.setAlmacen(obtenerAlmacen(cursor.getString(2)));
			ocDto.setEstado(cursor.getString(3));
			ocDto.setIniciador(cursor.getString(4));
			ocDto.setFecha(cursor.getString(5));
			ocDto.setProveedor(cursor.getString(6));
			ocDto.setFechaModificacion(cursor.getString(7));
			cursor.close();
			if(OrdenCompra.esValido(ocDto)) {
				if(cargarProductos) {
					ArrayList<Producto> productos = obtenerProductos(id);
					Iterator<Producto> i = productos.iterator();
					while(i.hasNext()) {
						ocDto.agregarProducto(i.next());
					}
				}
				return ocDto;
			}
		}
		return null;
	}
	
	public Producto obtenerProducto(String id, int ordenCompra) {
		Cursor cursor = db.obtener("productos", String.format("id='%s' AND orden='%s'", id, ordenCompra));
		if(cursor != null) {
			Producto productoDto = new Producto();
			productoDto.setId(cursor.getString(0));
			productoDto.setOrdenCompraId(cursor.getInt(1));
			productoDto.setNombre(cursor.getString(2));
			productoDto.setCantidadTotal(cursor.getDouble(3));
			productoDto.setCantidadRecibida(cursor.getDouble(4));
			productoDto.setFechaModificacion(cursor.getString(5));
			cursor.close();		
			return productoDto;
		}
		return null;
	}
	
	public ArrayList<Producto> obtenerProductos(int ordenCompra) {
		ArrayList<Producto> productos = new ArrayList<Producto>();
		Cursor cursor = db.obtenerTodos("productos", String.format("orden='%s'", ordenCompra));
		if(cursor != null) {
			while(cursor.moveToNext()) {
				Producto productoDto = new Producto();
				productoDto.setId(cursor.getString(0));
				productoDto.setOrdenCompraId(cursor.getInt(1));
				productoDto.setNombre(cursor.getString(2));
				productoDto.setCantidadTotal(cursor.getDouble(3));
				productoDto.setCantidadRecibida(cursor.getDouble(4));
				productoDto.setFechaModificacion(cursor.getString(5));
				cursor.close();		
				productos.add(productoDto);
			}
		}
		return productos;
	}
	
	public boolean guardarUsuario(Usuario usuario) {
		if(usuario != null) {
			ContentValues values = new ContentValues();
			values.put("clave", usuario.getClave());
			values.put("nombre", usuario.getNombre());
			values.put("activo", usuario.estaActivo() ? 1 : 0);
			values.put("permisoRecibir", usuario.tienePermisoRecibir() ? 1 : 0);
			values.put("fecha_modificacion", usuario.getFechaModificacionString());
			
			Usuario usuarioDB = obtenerUsuario(usuario.getUsuario(), true);
			if(usuarioDB != null) {
				if(usuarioDB.esMayorFechaModificacion(usuario)) {
					db.actualizar("usuarios", values, String.format("usuario='%s'", usuario.getUsuario()));
				}
			} else {
				values.put("usuario", usuario.getUsuario());
				db.insertar("usuarios", values);
			}
					
			if(usuario.tieneAlmacenes()) {
				String[] almacenesIds = new String[usuario.getCantidadAlmacenes()];
				int i = 0;
				Iterator<Almacen> iterator = usuario.obtenerAlmacenesIterator();
				while(iterator.hasNext()) {
					Almacen almacen = iterator.next();
					ContentValues values2 = new ContentValues();
					values2.put("usuario", usuario.getUsuario());
					values2.put("almacen", almacen.getId());
					almacenesIds[i] = "'" + almacen.getId() + "'";
					db.insertar("almacenes_usuarios", values2);
					i++;
				}
				db.borrarAlmacenesUsuarioExcepto(almacenesIds, usuario.getUsuario());
			} else {
				db.borrar("almacenes_usuarios", String.format("usuario='%s'", usuario.getUsuario()));
			}
			return true;
		}
		return false;
	}
	
	public boolean guardarAlmacen(Almacen almacen) {
		if(almacen != null) {
			ContentValues values = new ContentValues();
			values.put("nombre", almacen.getNombre());
			values.put("fecha_modificacion", almacen.getFechaModificacionString());
			
			Almacen almacenDB = obtenerAlmacen(almacen.getId());
			if(almacenDB != null) {
				if(almacenDB.esMayorFechaModificacion(almacen)) {
					return db.actualizar("almacenes", values, String.format("id='%s'", almacen.getId()));
				}
			} else {
				values.put("id", almacen.getId());
				return db.insertar("almacenes", values) != DB.ERROR;
			}
		} 
		return false;
	}
	
	public boolean guardarProducto(Producto producto) {
		if(producto != null) {
			ContentValues values = new ContentValues();
			values.put("orden", producto.getOrdenCompraId());
			values.put("nombre", producto.getNombre());
			values.put("total", producto.getCantidadTotal());
			values.put("recibido", producto.getCantidadRecibida());
			values.put("fecha_modificacion", producto.getFechaModificacionString());
			
			Producto productoDB = obtenerProducto(producto.getId(), producto.getOrdenCompraId());
			if(productoDB != null) {
				if(productoDB.esMayorFechaModificacion(producto)) {
					return db.actualizar("productos", values, String.format("id='%s'", producto.getId()));
				}
			} else {
				values.put("id", producto.getId());
				return db.insertar("productos", values) != DB.ERROR;
			}
		} 
		return false;
	}
	
	public boolean actualizarProducto(Producto producto) {
		if(producto != null) {
			ContentValues values = new ContentValues();
			values.put("orden", producto.getOrdenCompraId());
			values.put("nombre", producto.getNombre());
			values.put("total", producto.getCantidadTotal());
			values.put("recibido", producto.getCantidadRecibida());
			values.put("fecha_modificacion", producto.getFechaModificacionString());
			if(db.actualizar("productos", values, String.format("id='%s' AND orden='%s'", producto.getId(), producto.getOrdenCompraId()))) {
				return true;
			}
		} 
		return false;
	}
	
	public boolean guardarOrdenCompra(OrdenCompra oc) {
		if(oc != null) {
			ContentValues values = new ContentValues();
			values.put("usuario", oc.getUsuarioId());
			values.put("almacen", oc.getAlmacenId());
			values.put("iniciador", oc.getIniciador());
			values.put("proveedor", oc.getProveedor());
			values.put("fecha", oc.getFecha());
			values.put("iniciador", oc.getIniciador());
			values.put("fecha_modificacion", oc.getFechaModificacionString());
			if(oc.recepcionCompleta()) {
				values.put("estado", OrdenCompra.ESTADO_COMPLETO);
			} else {
				values.put("estado", OrdenCompra.ESTADO_AUTORIZADO);
			}
			
			OrdenCompra ocDB = obtenerOrdenCompra(oc.getId(), false);
			if(ocDB != null) {
				if(ocDB.esMayorFechaModificacion(oc)) {
					db.actualizar("ordenes", values, String.format("id='%s'", oc.getId()));
				}
			} else {
				values.put("id", oc.getId());
				db.insertar("ordenes", values);
			}
			Iterator<Producto> i = oc.obtenerProductosIterator();
			while(i.hasNext()) {
				Producto producto = i.next();
				guardarProducto(producto);
			}
			return true;
		} 
		return false;
	}
	
	public boolean actualizarOrdenCompra(OrdenCompra oc) {
		if(oc != null) {
			ContentValues values = new ContentValues();
			values.put("enviar", 1);
			if(oc.recepcionCompleta()) {
				values.put("estado", OrdenCompra.ESTADO_COMPLETO);
			} else {
				values.put("estado", OrdenCompra.ESTADO_AUTORIZADO);
			}
			if(db.actualizar("ordenes", values, String.format("id='%s'", oc.getId()))) {
				Iterator<Producto> i = oc.obtenerProductosIterator();
				while(i.hasNext()) {
					Producto producto = i.next();
					actualizarProducto(producto);
				}
				return true;
			}
		}
		return false;
	}
	
	public boolean actualizarOrdenCompraEnviada(OrdenCompra oc) {
		ContentValues values = new ContentValues();
		values.put("enviar", 0);
		if(oc.recepcionCompleta()) {
			values.put("estado", OrdenCompra.ESTADO_COMPLETO);
		} else {
			values.put("estado", OrdenCompra.ESTADO_AUTORIZADO);
		}
		return db.actualizar("ordenes", values, String.format("id='%s'", oc.getId()));
	}
	
	public void borrarOrdenesCompraExcepto(ArrayList<OrdenCompra> ordenes) {
		int size = ordenes.size();
		if(size > 0) {
			String[] condiciones = new String[size]; int i = 0;
			Iterator<OrdenCompra> iterator = ordenes.iterator();
			while(iterator.hasNext()) {
				OrdenCompra oc = iterator.next();
				condiciones[i] = String.format("(id='%s')", oc.getId()); i++;
			}
			db.borrar("ordenes", "NOT (" + Utils.implode(condiciones, " OR ") + ")");
		} else {
			db.borrar("ordenes", null);
		}
	}
}
